﻿using Paas.Pioneer.Domain.Shared.Dto.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp;
using Paas.Pioneer.Domain.Shared.Dto.Output;
using Paas.Pioneer.IOTNetworkCard.Domain.EmptyFlowSpeedFictitious;
using Paas.Pioneer.IOTNetworkCard.Application.Contracts.EmptyFlowSpeedFictitious.Dto.Input;
using Paas.Pioneer.IOTNetworkCard.Application.Contracts.EmptyFlowSpeedFictitious.Dto.Output;
using Paas.Pioneer.IOTNetworkCard.Application.Contracts.EmptyFlowSpeedFictitious;
using Paas.Pioneer.IOTNetworkCard.Domain.Package;
using System.Text.Json;
using JetBrains.Annotations;
using Volo.Abp.Domain.Repositories;

namespace Paas.Pioneer.IOTNetworkCard.Application.EmptyFlowSpeedFictitious
{
    /// <summary>
    /// 虚量配置表服务
    /// </summary>
    public class EmptyFlowSpeedFictitiousService : ApplicationService, IEmptyFlowSpeedFictitiousService
    {
        private readonly IEmptyFlowSpeedFictitiousRepository _emptyFlowSpeedFictitiousRepository;
        private readonly IPackageRepository _packageRepository;

        /// <summary>
        /// 构造函数
        /// </summary>
        public EmptyFlowSpeedFictitiousService(IEmptyFlowSpeedFictitiousRepository emptyFlowSpeedFictitiousRepository,
            IPackageRepository packageRepository)
        {
            _emptyFlowSpeedFictitiousRepository = emptyFlowSpeedFictitiousRepository;
            _packageRepository = packageRepository;
        }

        /// <summary>
        /// 查询虚量配置表
        /// </summary>
        /// <param name="packageId">套餐id</param>
        /// <returns></returns>
        public async Task<GetEmptyFlowSpeedFictitiousOutput> GetAsync(Guid packageId)
        {
            var result = await _emptyFlowSpeedFictitiousRepository.GetAsync(p => p.PackageId == packageId, x =>
                new GetEmptyFlowSpeedFictitiousOutput()
                {
                    PackageId = x.PackageId,
                    EmptyFlowFictitiousJson = x.EmptyFlowFictitiousJson,
                    SpeedFictitiousJson = x.SpeedFictitiousJson,
                    LimitDictionaryId = x.LimitDictionaryId,
                    Id = x.Id,
                });
            return result;
        }

        /// <summary>
        /// 查询分页虚量配置表
        /// </summary>
        /// <param name="input">入参</param>
        /// <returns></returns>
        public async Task<Page<GetEmptyFlowSpeedFictitiousPageListOutput>> GetPageListAsync(
            PageInput<GetEmptyFlowSpeedFictitiousPageListInput> input)
        {
            var data = await _emptyFlowSpeedFictitiousRepository.GetResponseOutputPageListAsync(x =>
                new GetEmptyFlowSpeedFictitiousPageListOutput
                {
                    PackageId = x.PackageId,
                    EmptyFlowFictitiousJson = x.EmptyFlowFictitiousJson,
                    SpeedFictitiousJson = x.SpeedFictitiousJson,
                    LastModificationTime = x.LastModificationTime,
                    CreationTime = x.CreationTime,
                    Id = x.Id,
                }, input: input);
            return data;
        }

        /// <summary>
        /// 新增/编辑虚量配置表
        /// </summary>
        /// <param name="input">入参</param>
        /// <returns></returns>
        [NotNull]
        public async Task AddOrUpdateEmptyQuantityAsync(AddEmptyFlowFictitiousInput input)
        {
            if (input.EmptyFlowFictitiousJson == null || input.EmptyFlowFictitiousJson.Count == 0)
            {
                throw new BusinessException("虚量配置不能为空");
            }

            var packageEntity = await _packageRepository.GetAsync(x => x.Id == input.PackageId, p =>
                new PackageEntity
                {
                    EmptyFlow = p.EmptyFlow,
                    RealFlow = p.RealFlow
                });

            if (packageEntity == null)
            {
                throw new BusinessException("不存在套餐数据");
            }

            var fictitiousConfigureDtos = input.EmptyFlowFictitiousJson.OrderBy(x => x.Sort);

            // 判断第一值是否是0
            if (fictitiousConfigureDtos.Min(x => x.Begin) != 0)
            {
                throw new BusinessException("虚量区间配置必须从0开始");
            }

            if (fictitiousConfigureDtos.Sum(x => x.Ratio) != packageEntity.RealFlow)
            {
                throw new BusinessException("配置的真量与套餐的真量不符");
            }

            //区间的总虚量---套餐的虚量
            if (fictitiousConfigureDtos.Sum(x => x.Fictitiou) != packageEntity.EmptyFlow)
            {
                throw new BusinessException("配置的虚量与套餐的虚量不符");
            }

            // 上次的真实流量
            var realFlowEnd = 0m;
            foreach (var item in fictitiousConfigureDtos)
            {
                // 区间的最小值和上一次的真实
                if (item.Begin != realFlowEnd)
                {
                    throw new BusinessException($"区间{item.Begin}-{item.End}的配置和上一个区间不相连，请重新配置");
                }

                realFlowEnd = item.End;
            }


            if (input.Id == null || input.Id.Value == Guid.Empty)
            {
                var emptyFlowEntity =
                    ObjectMapper.Map<AddEmptyFlowFictitiousInput, EmptyFlowSpeedFictitiousEntity>(input);
                emptyFlowEntity.EmptyFlowFictitiousJson = JsonSerializer.Serialize(input.EmptyFlowFictitiousJson);
                await _emptyFlowSpeedFictitiousRepository.InsertAsync(emptyFlowEntity);
                return;
            }

            var entity = await _emptyFlowSpeedFictitiousRepository.GetAsync(input.Id.Value);
            if (entity == null)
            {
                throw new BusinessException("数据不存在！");
            }

            entity.EmptyFlowFictitiousJson = JsonSerializer.Serialize(input.EmptyFlowFictitiousJson);
            await _emptyFlowSpeedFictitiousRepository.UpdateAsync(entity);
        }

        /// <summary>
        /// 新增限速配置表
        /// </summary>
        /// <param name="input">入参</param>
        /// <returns></returns>
        public async Task AddOrUpdateSpeedAsync(AddSpeedFictitiousInput input)
        {
            if (input.SpeedFictitiousJson == null || input.SpeedFictitiousJson.Count == 0)
            {
                throw new BusinessException("限速配置不能为空");
            }

            var packageEntity = await _packageRepository.GetAsync(x => x.Id == input.PackageId, p =>
                new PackageEntity
                {
                    EmptyFlow = p.EmptyFlow,
                    RealFlow = p.RealFlow
                });

            if (packageEntity == null)
            {
                throw new BusinessException("不存在套餐数据");
            }

            if (input.Id == null || input.Id.Value == Guid.Empty)
            {
                var speedEntity =
                    ObjectMapper.Map<AddSpeedFictitiousInput, EmptyFlowSpeedFictitiousEntity>(input);
                speedEntity.SpeedFictitiousJson = JsonSerializer.Serialize(input.SpeedFictitiousJson);
                speedEntity.LimitDictionaryId = input.LimitDictionaryId;
                await _emptyFlowSpeedFictitiousRepository.InsertAsync(speedEntity);
                return;
            }

            var entity = await _emptyFlowSpeedFictitiousRepository.GetAsync(input.Id.Value);
            if (entity == null)
            {
                throw new BusinessException("数据不存在！");
            }

            entity.SpeedFictitiousJson = JsonSerializer.Serialize(input.SpeedFictitiousJson);
            entity.LimitDictionaryId = input.LimitDictionaryId;
            await _emptyFlowSpeedFictitiousRepository.UpdateAsync(entity);
        }

        /// <summary>
        /// 删除虚量配置表
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns></returns>
        public async Task DeleteAsync(Guid id)
        {
            await _emptyFlowSpeedFictitiousRepository.DeleteAsync(m => m.Id == id);
        }

        /// <summary>
        /// 批量删除虚量配置表
        /// </summary>
        /// <param name="ids">主键集合</param>
        /// <returns></returns>
        public async Task BatchSoftDeleteAsync(IEnumerable<Guid> ids)
        {
            await _emptyFlowSpeedFictitiousRepository.DeleteAsync(x => ids.Contains(x.Id));
        }
    }
}